﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using GeoAPI.Geometries;
using NetTopologySuite.Geometries;
using NetTopologySuite.Planargraph;
using NetTopologySuite.Utilities;

namespace NetTopologySuite.Operation.Polygonize
{
	public class PolygonizeGraph : PlanarGraph
	{
		private static int GetDegreeNonDeleted(Node node)
		{
			IEnumerable<DirectedEdge> edges = node.OutEdges.Edges;
			int num = 0;
			IEnumerator<DirectedEdge> enumerator = edges.GetEnumerator();
			{
				while (enumerator.MoveNext())
				{
					if (!((PolygonizeDirectedEdge)enumerator.Current).IsMarked)
					{
						num++;
					}
				}
			}
			return num;
		}

		private static int GetDegree(Node node, long label)
		{
			IEnumerable<DirectedEdge> edges = node.OutEdges.Edges;
			int num = 0;
			IEnumerator<DirectedEdge> enumerator = edges.GetEnumerator();
			{
				while (enumerator.MoveNext())
				{
					if (((PolygonizeDirectedEdge)enumerator.Current).Label == label)
					{
						num++;
					}
				}
			}
			return num;
		}

		public static void DeleteAllEdges(Node node)
		{
			foreach (DirectedEdge directedEdge in node.OutEdges.Edges)
			{
				PolygonizeDirectedEdge polygonizeDirectedEdge = (PolygonizeDirectedEdge)directedEdge;
				polygonizeDirectedEdge.Marked = true;
				PolygonizeDirectedEdge polygonizeDirectedEdge2 = (PolygonizeDirectedEdge)polygonizeDirectedEdge.Sym;
				if (polygonizeDirectedEdge2 != null)
				{
					polygonizeDirectedEdge2.Marked = true;
				}
			}
		}

		public PolygonizeGraph(IGeometryFactory factory)
		{
			this._factory = factory;
		}

		public void AddEdge(ILineString line)
		{
			if (line.IsEmpty)
			{
				return;
			}
			Coordinate[] array = CoordinateArrays.RemoveRepeatedPoints(line.Coordinates);
			if (array.Length < 2)
			{
				return;
			}
			Coordinate pt = array[0];
			Coordinate pt2 = array[array.Length - 1];
			Node node = this.GetNode(pt);
			Node node2 = this.GetNode(pt2);
			DirectedEdge de = new PolygonizeDirectedEdge(node, node2, array[1], true);
			DirectedEdge de2 = new PolygonizeDirectedEdge(node2, node, array[array.Length - 2], false);
			Edge edge = new PolygonizeEdge(line);
			edge.SetDirectedEdges(de, de2);
			base.Add(edge);
		}

		private Node GetNode(Coordinate pt)
		{
			Node node = base.FindNode(pt);
			if (node == null)
			{
				node = new Node(pt);
				base.Add(node);
			}
			return node;
		}

		private void ComputeNextCWEdges()
		{
			foreach (Node node in base.Nodes)
			{
				PolygonizeGraph.ComputeNextCWEdges(node);
			}
		}

		private static void ConvertMaximalToMinimalEdgeRings(IEnumerable<DirectedEdge> ringEdges)
		{
			foreach (DirectedEdge directedEdge in ringEdges)
			{
				PolygonizeDirectedEdge polygonizeDirectedEdge = (PolygonizeDirectedEdge)directedEdge;
				long label = polygonizeDirectedEdge.Label;
				IEnumerable<Node> enumerable = PolygonizeGraph.FindIntersectionNodes(polygonizeDirectedEdge, label);
				if (enumerable != null)
				{
					foreach (Node node in enumerable)
					{
						PolygonizeGraph.ComputeNextCCWEdges(node, label);
					}
				}
			}
		}

		private static IEnumerable<Node> FindIntersectionNodes(PolygonizeDirectedEdge startDE, long label)
		{
			PolygonizeDirectedEdge polygonizeDirectedEdge = startDE;
			IList<Node> list = null;
			do
			{
				Node fromNode = polygonizeDirectedEdge.FromNode;
				if (PolygonizeGraph.GetDegree(fromNode, label) > 1)
				{
					if (list == null)
					{
						list = new List<Node>();
					}
					list.Add(fromNode);
				}
				polygonizeDirectedEdge = polygonizeDirectedEdge.Next;
				Assert.IsTrue(polygonizeDirectedEdge != null, "found null DE in ring");
				Assert.IsTrue(polygonizeDirectedEdge == startDE || !polygonizeDirectedEdge.IsInRing, "found DE already in ring");
			}
			while (polygonizeDirectedEdge != startDE);
			return list;
		}

		public IList<EdgeRing> GetEdgeRings()
		{
			this.ComputeNextCWEdges();
			PolygonizeGraph.Label(this.dirEdges, -1L);
			PolygonizeGraph.ConvertMaximalToMinimalEdgeRings(PolygonizeGraph.FindLabeledEdgeRings(this.dirEdges));
			IList<EdgeRing> list = new List<EdgeRing>();
			foreach (DirectedEdge directedEdge in this.dirEdges)
			{
				PolygonizeDirectedEdge polygonizeDirectedEdge = (PolygonizeDirectedEdge)directedEdge;
				if (!polygonizeDirectedEdge.IsMarked && !polygonizeDirectedEdge.IsInRing)
				{
					EdgeRing item = this.FindEdgeRing(polygonizeDirectedEdge);
					list.Add(item);
				}
			}
			return list;
		}

		private static IList<DirectedEdge> FindLabeledEdgeRings(IEnumerable<DirectedEdge> dirEdges)
		{
			IList<DirectedEdge> list = new List<DirectedEdge>();
			long num = 1L;
			foreach (DirectedEdge directedEdge in dirEdges)
			{
				PolygonizeDirectedEdge polygonizeDirectedEdge = (PolygonizeDirectedEdge)directedEdge;
				if (!polygonizeDirectedEdge.IsMarked && polygonizeDirectedEdge.Label < 0L)
				{
					list.Add(polygonizeDirectedEdge);
					PolygonizeGraph.Label(EdgeRing.FindDirEdgesInRing(polygonizeDirectedEdge), num);
					num += 1L;
				}
			}
			return list;
		}

		public IList<ILineString> DeleteCutEdges()
		{
			this.ComputeNextCWEdges();
			PolygonizeGraph.FindLabeledEdgeRings(this.dirEdges);
			IList<ILineString> list = new List<ILineString>();
			foreach (DirectedEdge directedEdge in this.dirEdges)
			{
				PolygonizeDirectedEdge polygonizeDirectedEdge = (PolygonizeDirectedEdge)directedEdge;
				if (!polygonizeDirectedEdge.IsMarked)
				{
					PolygonizeDirectedEdge polygonizeDirectedEdge2 = (PolygonizeDirectedEdge)polygonizeDirectedEdge.Sym;
					if (polygonizeDirectedEdge.Label == polygonizeDirectedEdge2.Label)
					{
						polygonizeDirectedEdge.Marked = true;
						polygonizeDirectedEdge2.Marked = true;
						PolygonizeEdge polygonizeEdge = (PolygonizeEdge)polygonizeDirectedEdge.Edge;
						list.Add(polygonizeEdge.Line);
					}
				}
			}
			return list;
		}

		private static void Label(IEnumerable<DirectedEdge> dirEdges, long label)
		{
			foreach (DirectedEdge directedEdge in dirEdges)
			{
				((PolygonizeDirectedEdge)directedEdge).Label = label;
			}
		}

		private static void ComputeNextCWEdges(Node node)
		{
			DirectedEdgeStar outEdges = node.OutEdges;
			PolygonizeDirectedEdge polygonizeDirectedEdge = null;
			PolygonizeDirectedEdge polygonizeDirectedEdge2 = null;
			foreach (DirectedEdge directedEdge in outEdges.Edges)
			{
				PolygonizeDirectedEdge polygonizeDirectedEdge3 = (PolygonizeDirectedEdge)directedEdge;
				if (!polygonizeDirectedEdge3.IsMarked)
				{
					if (polygonizeDirectedEdge == null)
					{
						polygonizeDirectedEdge = polygonizeDirectedEdge3;
					}
					if (polygonizeDirectedEdge2 != null)
					{
						((PolygonizeDirectedEdge)polygonizeDirectedEdge2.Sym).Next = polygonizeDirectedEdge3;
					}
					polygonizeDirectedEdge2 = polygonizeDirectedEdge3;
				}
			}
			if (polygonizeDirectedEdge2 != null)
			{
				((PolygonizeDirectedEdge)polygonizeDirectedEdge2.Sym).Next = polygonizeDirectedEdge;
			}
		}

		private static void ComputeNextCCWEdges(Node node, long label)
		{
			DirectedEdgeStar outEdges = node.OutEdges;
			PolygonizeDirectedEdge polygonizeDirectedEdge = null;
			PolygonizeDirectedEdge polygonizeDirectedEdge2 = null;
			IList<DirectedEdge> edges = outEdges.Edges;
			for (int i = edges.Count - 1; i >= 0; i--)
			{
				PolygonizeDirectedEdge polygonizeDirectedEdge3 = (PolygonizeDirectedEdge)edges[i];
				PolygonizeDirectedEdge polygonizeDirectedEdge4 = (PolygonizeDirectedEdge)polygonizeDirectedEdge3.Sym;
				PolygonizeDirectedEdge polygonizeDirectedEdge5 = null;
				if (polygonizeDirectedEdge3.Label == label)
				{
					polygonizeDirectedEdge5 = polygonizeDirectedEdge3;
				}
				PolygonizeDirectedEdge polygonizeDirectedEdge6 = null;
				if (polygonizeDirectedEdge4.Label == label)
				{
					polygonizeDirectedEdge6 = polygonizeDirectedEdge4;
				}
				if (polygonizeDirectedEdge5 != null || polygonizeDirectedEdge6 != null)
				{
					if (polygonizeDirectedEdge6 != null)
					{
						polygonizeDirectedEdge2 = polygonizeDirectedEdge6;
					}
					if (polygonizeDirectedEdge5 != null)
					{
						if (polygonizeDirectedEdge2 != null)
						{
							polygonizeDirectedEdge2.Next = polygonizeDirectedEdge5;
							polygonizeDirectedEdge2 = null;
						}
						if (polygonizeDirectedEdge == null)
						{
							polygonizeDirectedEdge = polygonizeDirectedEdge5;
						}
					}
				}
			}
			if (polygonizeDirectedEdge2 != null)
			{
				Assert.IsTrue(polygonizeDirectedEdge != null);
				polygonizeDirectedEdge2.Next = polygonizeDirectedEdge;
			}
		}

		private EdgeRing FindEdgeRing(PolygonizeDirectedEdge startDE)
		{
			EdgeRing edgeRing = new EdgeRing(this._factory);
			edgeRing.Build(startDE);
			return edgeRing;
		}

		public ICollection<ILineString> DeleteDangles()
		{
			IEnumerable<Node> enumerable = base.FindNodesOfDegree(1);
			HashSet<ILineString> hashSet = new HashSet<ILineString>();
			Stack<Node> stack = new Stack<Node>();
			IEnumerator<Node> enumerator = enumerable.GetEnumerator();
			{
				while (enumerator.MoveNext())
				{
					Node item = enumerator.Current;
					stack.Push(item);
				}
				goto IL_D8;
			}
			IL_42:
			Node node = stack.Pop();
			PolygonizeGraph.DeleteAllEdges(node);
			foreach (DirectedEdge directedEdge in node.OutEdges.Edges)
			{
				PolygonizeDirectedEdge polygonizeDirectedEdge = (PolygonizeDirectedEdge)directedEdge;
				polygonizeDirectedEdge.Marked = true;
				PolygonizeDirectedEdge polygonizeDirectedEdge2 = (PolygonizeDirectedEdge)polygonizeDirectedEdge.Sym;
				if (polygonizeDirectedEdge2 != null)
				{
					polygonizeDirectedEdge2.Marked = true;
				}
				PolygonizeEdge polygonizeEdge = (PolygonizeEdge)polygonizeDirectedEdge.Edge;
				hashSet.Add(polygonizeEdge.Line);
				Node toNode = polygonizeDirectedEdge.ToNode;
				if (PolygonizeGraph.GetDegreeNonDeleted(toNode) == 1)
				{
					stack.Push(toNode);
				}
			}
			IL_D8:
			if (stack.Count == 0)
			{
				ILineString[] array = new ILineString[hashSet.Count];
				hashSet.CopyTo(array, 0);
				return new ReadOnlyCollection<ILineString>(array);
			}
			goto IL_42;
		}

		public void ComputeDepthParity()
		{
			for (;;)
			{
				PolygonizeDirectedEdge polygonizeDirectedEdge = null;
				if (polygonizeDirectedEdge == null)
				{
					break;
				}
				this.ComputeDepthParity(polygonizeDirectedEdge);
			}
		}

		private void ComputeDepthParity(PolygonizeDirectedEdge de)
		{
		}

		private readonly IGeometryFactory _factory;
	}
}
